package com.wongsir.springioc;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import cn.hutool.core.util.XmlUtil;

/**
 * @descrip 用反射技术实现IOC原理:获取对象并创建对象实例，并通过map集合管理对象。
 * 			而在spring中管理对象和数据结构的是bean，context就是多个bean关系的集合，提供生存环境并维护bean之间的关系，
 * 			这个关系集合又叫IOC容器
 * @author wongsir
 * @time 2018年7月29日
 */
public class ClassPathXmlApplicationContext implements BeanFactory{

	private Map<String,Object> beans = new HashMap<>();
	
	public ClassPathXmlApplicationContext() throws Exception{
		Document doc = XmlUtil.readXML("beans.xml");
		Element root = XmlUtil.getRootElement(doc);//获取根元素
		List<Element> eList = XmlUtil.getElements(root, "bean");//获取名字为bean的所有元素
		
		for(Element element : eList) {
			String id = element.getAttribute("id");
			String clazz = element.getAttribute("class");
			//以下使用反射实现：获取对象并创建实例
			Object o = Class.forName(clazz).newInstance();
			//将创建好的对象实例放到集合中，后续用到直接取出即可，而不用主动创建
			beans.put(id, o);
			
			
			//以上的逻辑实现了一次获取多个“xml配置文件中同级”的对象
			//下面实现获取嵌套的对象集合(逻辑基本跟上面一样，都是用反射技术)
			for(Element propertyElement : XmlUtil.getElements(element, "property")) {
				String name = propertyElement.getAttribute("name");
				String bean = propertyElement.getAttribute("bean");
				Object beanObject = beans.get(bean);
				
				//setter方式注入（其他的注入方式还有：接口注入、构造函数注入）
				String methodName = "set"+name.substring(0, 1).toUpperCase() + name.substring(1);
				System.out.println("method name = "+methodName);
				
				Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces());
				m.invoke(o, beanObject);
			}
			
		}
		
		
	}
	
	public Object getBean(String id) {
		return beans.get(id);
	}

}
